#include "HndToRawData.h"
#include <memory.h>

//! This function converts the unfiltered hnd file data
//! and converts it to raw image file data.
//! \param[in] hnd The unfiltered hnd image file data
//! \param[out] raw The pointer to write the raw file
//! data to. The memory that the pointer points to
//! must be allocated by (sizeof(uint32) * HND_ROWS * HND_COLS).
void HndToRawData(const void* hnd, uint32* raw)
{
	// Pointer to lookup table
	const uint8* const lut = (const uint8*)hnd + 1024;

	// Pointer to uncompressed pixel data
	const uint32* const pixels = (const uint32*)(lut + ((HND_COLS * (HND_ROWS - 1)) / 4));

	// Pointer to pixel differences (compressed pixel data)
	const void* diffs = (const void*)(pixels + HND_COLS + 1);

	// Copy the uncompressed pixels from the first row
	memcpy(raw, pixels, HND_COLS * sizeof(uint32));
	
	// Index of pixel we are on.
	uint i = HND_COLS;
	
	// Copy the uncompressed pixel from the second row
	raw[i] = pixels[i];

	++i;

	uint r11, r12, r21, lutoff, lutid;
	uint8 lutval;
	int diff;
	for (lutval = lutoff = lutid = 0; i < HND_ROWS * HND_COLS; ++i)
	{
		r11 = raw[i - HND_COLS - 1];
		r12 = raw[i - HND_COLS];
		r21 = raw[i - 1];
		lutval = lut[lutid];

		// Since the lookup table is a table of 2 bit values,
		// we must keep an offset variable to track how many
		// entries (of two bits) we have gone into in a uint8.
		switch (lutoff)
		{
		case 0:
			// 0x03 equals 00000011
			lutval = lutval & 0x03;
			++lutoff;
			break;
		case 1:
			// 0x0C equals 00001100
			lutval = (lutval & 0x0C) >> 2;
			++lutoff;
			break;
		case 2:
			// 0x30 equals 00110000
			lutval = (lutval & 0x30) >> 4;
			++lutoff;
			break;
		case 3:
			// 0xC0 equals 11000000
			lutval = (lutval & 0xC0) >> 6;
			lutoff = 0;
			++lutid;
			break;
		}
		char bchar;
		short bshort;
		long blong;
		switch (lutval)
		{
		case 0:
			bchar =(char) (*((const char *)diffs));
			++((const int8*&)diffs);
			diff = (long)bchar;
			break;
		case 1:
			bshort =(short)( *((const short *)diffs));
			++((const short*&)diffs);
			diff = (long)bshort;
			break;
		case 2:
			blong =(long)( *((const long *)diffs));
			++((const long*&)diffs);
			diff=(long)blong;
			break;

		// The difference is one int8
		//case 0:
		//	diff = *((const int8*)diffs);
		//	++((const int8*&)diffs);
		//	break;
		//// The difference is two bytes
		//case 1:
		//	diff = *((const int16*)diffs);
		//	++((const int16*&)diffs);
		//	break;
		//// The difference is four bytes
		//case 2:
		//	diff = *((const int32*)diffs);
		//	++((const int32*&)diffs);
		//	break;
		}

		if (((float)r21 + (float)diff - (float)r11 + (float)r12) > 0xFFFFFFFF)
		{
			//printf("!!!!!!!!!!!!!!!\n");
			//_asm int 3;
		}
		//float f = ((float)r21) + ((float)diff) - ((float)r11) + ((float)r12);
		raw[i] = r21 + diff - r11 + r12;
#ifdef OUTPUT_DBG
		fprintf(dbgFile, "r11 = %x, r12 = %x, r21 = %x, diff = %d\n",
			r11, r12, r21, diff);
#endif
		//raw[i] = (uint)f;
	}
}